package com.github.cdisk.xtrans.parser;

import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.cdisk.xtrans.connect.Connect;
import com.github.cdisk.xtrans.core.BaseComponent;
import com.github.cdisk.xtrans.core.ConfigFile;

public class ConfigFileParser {
	
	private static ObjectMapper objectMapper = new ObjectMapper();
	static {
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // json中多的字段，不报错
//		SimpleModule module = new SimpleModule();
//		ComponentSerializable componentSerializable = new ComponentSerializable();
//		module.addSerializer(BaseComponent.class, componentSerializable);
//		ComponentDeserializer componentDeserializer = new ComponentDeserializer();
//		module.addDeserializer(BaseComponent.class, componentDeserializer);
//		objectMapper.registerModule(module);
	}

//	public static void main(String[] args) throws IOException {
//		ConfigFile config = read("E:\\eclipse_rcp\\xtrans\\text.xdt");
//		write("E:\\eclipse_rcp\\xtrans\\text_2.xdt", config);
//	}

	public static ConfigFile read(String fileString) throws IOException {
		File file = new File(fileString);
		ConfigFile config = objectMapper.readValue(file, ConfigFile.class);
		/* 去掉为空的元件，防止文件错误时加载报错。 */
		for (int i = 0; i < config.components.size(); i++) {
			BaseComponent component = config.components.get(i);
			if (component == null) {
				config.components.remove(i);
				i--;
			}
		}
		/* 去掉为空的连接，防止文件错误时加载报错。 */
		for (int i = 0; i < config.connects.size(); i++) {
			Connect connect = config.connects.get(i);
			if (connect == null) {
				config.connects.remove(i);
				i--;
			}
		}
		return config;
	}

	public static void write(String file, ConfigFile config) throws JsonGenerationException, JsonMappingException, IOException {
		objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File(file), config);
	}

	/**
	 * 原件对象序列化
	 * @author cdisk
	 *
	 */
//	public static class ComponentSerializable extends JsonSerializer<BaseComponent> {
//
//		@Override
//		public void serialize(BaseComponent value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
//
//			Class<?> clazz = value.getClass(); // 找出元件是什么类型
//
//			gen.writeStartObject();
//			gen.writeStringField("_typeName", clazz.getName());
//			try {
//				List<Field> fields = new ArrayList<>();
//				do {
//					for (Field field : clazz.getDeclaredFields()) {
//						fields.add(field); // 把元件类型中的普通属性全部取出来
//					}
//				} while (BaseComponent.class.isAssignableFrom(clazz = clazz.getSuperclass())); // 循环查找父类，直到不是BaseComponent
//				
//				for (Field field : fields) { // 循环处理元件属性
//					Attribute attribute = field.getAnnotation(Attribute.class); // 获取其属性说明注解
//					if (attribute == null) continue; // 判断属性说明注册是否存在，存在则进行序列化处理，不存在则跳过。
//					field.setAccessible(true); // 设置属性可访问
//					Class<?> typeClass = field.getType(); // 获取属性的类型
//					String name = field.getName();
//					Object object = field.get(value);
//					if (object == null) {
//						gen.writeNullField(field.getName());
//					} else if (BaseComponent.class.isAssignableFrom(typeClass)) { // 如果属性是元件类型，说明是引用其他元件，则只需输出保存其他元件ID。
//						BaseComponent target = (BaseComponent) object;
//						gen.writeStringField(name, target.getId());
//					} else if (Connect.class.isAssignableFrom(typeClass)) { // 如果属性是连接类型，说明是引用连接，则只需输出保存连接ID。
//						Connect target = (Connect) object;
//						gen.writeStringField(name, target.getId());
//					} else { // 其他属性序列化处理
//						gen.writeObjectField(name, object);
//					}
//				}
//			} catch (IllegalAccessException e) {
//				e.printStackTrace();
//			}
//			gen.writeEndObject();
//		}
//
//	};

	/**
	 * 元件对象反序列化
	 * @author cdisk
	 *
	 */
//	public static class ComponentDeserializer extends JsonDeserializer<BaseComponent> {
//
//		@Override
//		public BaseComponent deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
//			JsonNode node = objectMapper.readTree(p);
//			String typeName = node.get("_typeName").asText();
//			try {
//				Class<?> clazz = Class.forName(typeName);
//				Object obj = clazz.newInstance(); // 立刻初始化，否则do while会覆盖clazz变量。
//				List<Field> fields = new ArrayList<>(); // 存储所有属性
//				do {
//					for (Field field : clazz.getDeclaredFields()) {
//						fields.add(field); // 把元件类型中的普通属性全部取出来
//					}
//				} while (BaseComponent.class.isAssignableFrom(clazz = clazz.getSuperclass())); // 循环查找父类，直到不是BaseComponent
//				
//				for (Field field : fields) {
//					Attribute attribute = field.getAnnotation(Attribute.class);
//					if (attribute == null) continue;
//					field.setAccessible(true);
//					String fieldName = field.getName();
//					Class<?> fieldType = field.getType();
//					if (BaseComponent.class.isAssignableFrom(fieldType)) { // 引用元件处理办法，存储为ID，要关联还原为元件对象。
//						BaseComponent component = new BaseComponent() { // 没办法完美还原，只有还原个ID存储，在外部再次循环根据ID重新进行引用赋值。
//							@Override
//							public int execute(Map<String, Object> input) {
//								return 0;
//							}
//						};
//						component.setId(node.get(fieldName).asText());
//						field.set(obj, component);
//						System.out.println("BaseComponent：" + fieldName);
//					} else if (Connect.class.isAssignableFrom(fieldType)) { // 没办法完美还原，只有还原个ID存储，在外部再次循环根据ID重新进行引用赋值。
//						Connect connect = new Connect();
//						connect.setId(node.get(fieldName).asText());
//						field.set(obj, connect);
//						System.out.println("Connect：" + fieldName);
//					} else { // 其他属性还原处理
//						System.out.println("Other：" + fieldName);
//						JsonNode n = node.get(field.getName());
//						Object value = objectMapper.readValue(objectMapper.writeValueAsString(n), fieldType); // TODO 此处应该调用jackson自身解析办法。
//						field.set(obj, value);
//					}
//				}
//				return (BaseComponent) obj;
//			} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
//				e.printStackTrace();
//			}
//			return null;
//		}
//
//	}

}
